package com.whjfxx.terminal.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.whjfxx.terminal.biz.enums.YesNoEnum;
import com.whjfxx.terminal.biz.mapper.PoFuncTerminalMapper;
import com.whjfxx.terminal.biz.mapper.PoTerminalMapper;
import com.whjfxx.terminal.biz.param.SearchParam;
import com.whjfxx.terminal.biz.param.TerminalPageParam;
import com.whjfxx.terminal.biz.param.TerminalParam;
import com.whjfxx.terminal.biz.service.PoAppService;
import com.whjfxx.terminal.biz.service.PoFuncService;
import com.whjfxx.terminal.biz.service.PoTerminalService;
import com.whjfxx.terminal.biz.service.SysOrganizationService;
import com.whjfxx.terminal.biz.vo.TerminalVo;
import com.whjfxx.terminal.entity.*;
import com.whjfxx.terminal.exceptions.BizException;
import com.whjfxx.terminal.utils.BeanUtils;
import com.whjfxx.terminal.utils.PageUtils;
import com.whjfxx.terminal.utils.QueryUtil;
import jodd.util.StringUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by b.c on 2022/6/7 16:28
 */
@Service
public class PoTerminalServiceImpl extends ServiceImpl<PoTerminalMapper, PoTerminal> implements PoTerminalService {

    @Autowired
    PoAppService poAppService;

    @Autowired
    PoFuncService poFuncService;

    @Autowired
    SysOrganizationService sysOrganizationService;

    @Override
    public Page<TerminalVo> pageList(SearchParam<TerminalPageParam> searchParam) {
        LambdaQueryWrapper<PoTerminal> wrapper = new LambdaQueryWrapper();
        QueryUtil.search(searchParam, TerminalPageParam.class, (pageParam) -> {
            if (StringUtils.isNotBlank(pageParam.getSn())) {
                wrapper.like(PoTerminal::getSn, pageParam.getSn());
            }
            if (StringUtils.isNotBlank(pageParam.getAppName())) {
                wrapper.inSql(PoTerminal::getAppId, "select id from po_app where app_name like concat('%', '" + pageParam.getAppName() + "', '%') ");
            }
            if (StringUtils.isNotBlank(pageParam.getFuncName())) {
                wrapper.inSql(PoTerminal::getFuncId, "select id from po_func where func_name like concat('%', '" + pageParam.getFuncName() + "', '%') ");
            }
            if (StringUtils.isNotBlank(pageParam.getTerminalType())) {
                wrapper.like(PoTerminal::getTerminalType, pageParam.getTerminalType());
            }
            if (Objects.nonNull(pageParam.getStatus())) {
                wrapper.eq(PoTerminal::getStatus, pageParam.getStatus());
            }
        });
        wrapper.orderByDesc(PoTerminal::getCreateTime);
        this.page(searchParam, wrapper);
        Page<PoTerminal> page = PageUtils.buildPage(searchParam);

        if (CollectionUtils.isEmpty(page.getRecords())) {
            return PageUtils.convertEmpty(page);
        }

        List<Long> appIds = new ArrayList<>(page.getRecords().size());
        List<Long> funcIds = new ArrayList<>(page.getRecords().size());

        for (PoTerminal record : page.getRecords()) {
            appIds.add(record.getAppId());
            funcIds.add(record.getFuncId());
        }

        Collection<PoApp> poApps = poAppService.listByIds(appIds);
        Map<Long, PoApp> poAppMap = poApps.stream().collect(Collectors.toMap(PoApp::getId, Function.identity()));

        Collection<PoFunc> poFuncs = poFuncService.listByIds(funcIds);
        Map<Long, PoFunc> poFuncMap = poFuncs.stream().collect(Collectors.toMap(PoFunc::getId, Function.identity()));

        List<Long> orgIds = poApps.stream().map(a -> a.getOrganizationId()).filter(Objects::nonNull).collect(Collectors.toList());
        Collection<SysOrganization> organizations = sysOrganizationService.listByIds(orgIds);
        Map<Long, SysOrganization> organizationMap = organizations.stream().collect(Collectors.toMap(SysOrganization::getId, Function.identity()));


        Page<TerminalVo> pageVo = PageUtils.convert(page, TerminalVo.class, (src, target) -> {
            PoApp poApp = poAppMap.get(src.getAppId());
            if (Objects.nonNull(poApp)) {
                target.setAppName(poApp.getAppName());
                SysOrganization organization = organizationMap.get(poApp.getOrganizationId());
                if (Objects.nonNull(organization)) {
                    target.setOrgName(organization.getOrganizationName());
                }
            }
            PoFunc poFunc = poFuncMap.get(src.getFuncId());
            if (Objects.nonNull(poFunc)) {
                target.setFuncName(poFunc.getFuncName());
            }
        });
        return pageVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertSave(TerminalParam param, String addType) {
        // 查询sn码是否已经存在
        PoTerminal poTerminal = this.getBySnAndFuncId(param.getSn(), param.getFuncId());
        if (Objects.nonNull(poTerminal)) {
            throw BizException.build("序列号功能已经存在");
        }

        // 校验应用是否存在
        PoApp poApp =  poAppService.getById(param.getAppId());
        if (Objects.isNull(poApp)) {
            throw BizException.build("应用信息不存在");
        }

        PoFunc poFunc = poFuncService.getById(param.getFuncId());
        if (Objects.isNull(poFunc)) {
            throw BizException.build("功能信息不存在");
        }

        poTerminal = new PoTerminal();
        BeanUtils.copyProperties(param, poTerminal);
        poTerminal.setActiveStatus(YesNoEnum.NO.status);
        poTerminal.setStatus(YesNoEnum.YES.status);

        if (StringUtils.isBlank(addType)) {
            poTerminal.setAddType("manual");
        } else {
            poTerminal.setAddType(addType);
        }
        poTerminal.setCreateTime(LocalDateTime.now());
        poTerminal.setUpdateTime(LocalDateTime.now());

        this.baseMapper.insert(poTerminal);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSave(TerminalParam param) {
        // 查询sn码是否已经存在
        PoTerminal poTerminal = this.getBySnAndFuncId(param.getSn(), param.getFuncId());
        if (Objects.isNull(poTerminal)) {
            throw BizException.build("序列号信息不存在");
        }

        if (!poTerminal.getId().equals(param.getId())) {
            throw BizException.build("参数校验错误");
        }

        // 校验应用是否存在
        PoApp poApp =  poAppService.getById(param.getAppId());
        if (Objects.isNull(poApp)) {
            throw BizException.build("应用信息不存在");
        }

        PoFunc poFunc = poFuncService.getById(param.getFuncId());
        if (Objects.isNull(poFunc)) {
            throw BizException.build("功能信息不存在");
        }

        poTerminal = new PoTerminal();
        BeanUtils.copyProperties(param, poTerminal);
        poTerminal.setActiveStatus(YesNoEnum.NO.status);
        poTerminal.setStatus(YesNoEnum.YES.status);
        poTerminal.setUpdateTime(LocalDateTime.now());

        this.baseMapper.updateById(poTerminal);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        if (Objects.isNull(id)) {
            throw BizException.build("参数错误");
        }
        PoTerminal poTerminal = this.getById(id);
        if (Objects.isNull(poTerminal)) {
            throw BizException.build("设备信息不存在");
        }

        if (null != poTerminal.getActiveStatus() && YesNoEnum.YES.status == poTerminal.getActiveStatus()) {
            throw BizException.build("设备已激活");
        }
        this.baseMapper.logicDelete(id, LocalDateTime.now());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void import2Terminal(String uuid) {
        // 更新 数据导入
    }

    @Override
    public void disable(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw BizException.build("参数错误");
        }
        Collection<PoTerminal> terminals = this.listByIds(ids);
        if (CollectionUtils.isEmpty(terminals)) {
            throw BizException.build("设备信息不存在");
        }
        for (PoTerminal terminal : terminals) {
            terminal.setStatus(YesNoEnum.NO.status);
            terminal.setUpdateTime(LocalDateTime.now());
            this.updateById(terminal);
        }
    }

    @Override
    public void enable(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw BizException.build("参数错误");
        }
        Collection<PoTerminal> terminals = this.listByIds(ids);
        if (CollectionUtils.isEmpty(terminals)) {
            throw BizException.build("设备信息不存在");
        }
        for (PoTerminal terminal : terminals) {
            terminal.setStatus(YesNoEnum.YES.status);
            terminal.setUpdateTime(LocalDateTime.now());
            this.updateById(terminal);
        }
    }

    @Override
    public List<PoTerminal> getBySn(String sn) {
        if (StringUtils.isBlank(sn)) {
            throw new IllegalArgumentException("参数错误");
        }
        LambdaQueryWrapper<PoTerminal> wrapper = new LambdaQueryWrapper();
        wrapper.eq(PoTerminal::getSn, sn);
        return this.list(wrapper);
    }

    /**
     * 根据sn查询
     * @param sn
     * @return
     */
    @Override
    public PoTerminal getBySnAndFuncId(String sn, Long funcId) {
        if (StringUtils.isBlank(sn) || Objects.isNull(funcId)) {
            throw new IllegalArgumentException("参数错误");
        }
        LambdaQueryWrapper<PoTerminal> wrapper = new LambdaQueryWrapper();
        wrapper.eq(PoTerminal::getSn, sn);
        wrapper.eq(PoTerminal::getFuncId, funcId);
        return this.getOne(wrapper);
    }

    /**
     * 根据sn查询
     * @param sn
     * @return
     */
    @Override
    public PoTerminal getBySnAndFuncName(String sn, String funcName) {
        if (StringUtils.isBlank(sn) || StringUtil.isBlank(funcName)) {
            throw new IllegalArgumentException("参数错误");
        }
        return this.baseMapper.listBySnAndFuncName(sn, funcName);
    }
}
